package com.demboos.galaxy.radio.widget;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;

public class GalaxyRadioService extends Service {

	private static final int BAND_76000_108000_kHz = 0x2;

	private static final int BAND_76000_90000_kHz = 0x3;

	private static final int BAND_87500_108000_kHz = 0x1;

	private static final int CHAN_SPACING_100_kHz = 0xa;

	private static final int CHAN_SPACING_200_kHz = 0x14;

	private static final int CHAN_SPACING_50_kHz = 0x5;

	private static final int DE_TIME_CONSTANT_50 = 0x1;

	private static final int DE_TIME_CONSTANT_75 = 0x0;

	private static final int RADIO_AUDIO_STREAM = 0xa;

	private static final String FM_RADIO_SERVICE_NAME = "FMPlayer";

	public static final String SAMSUNG_PACKAGE_NAME = "com.sec.android.app.fm";

	public static final String CMDAPPWIDGETUPDATE = "appwidgetupdate";
	public static final String CMDNAME = "command";

	// internal commands for play control
	public static final String NEXT_ACTION_INTERNAL = "com.demboos.galaxy.radio.widget.next";
	public static final String PREV_ACTION_INTERNAL = "com.demboos.galaxy.radio.widget.prev";
	public static final String TOGGLEPAUSE_ACTION_INTERNAL = "com.demboos.galaxy.radio.widget.togglepause";
	public static final String SCAN_CHANNELS_ACTION_INTERNAL = "com.demboos.galaxy.radio.widget.scan";

	public static final String SERVICECMDX = "com.demboos.galaxy.radio.widget.radioservicecommand";

	static final String TAG = "GalaxySRadioWidget";
	
	public static GalaxyRadioService INSTANCE;

	private GalaxyRadioAppWidgetProvider mAppWidgetProvider = GalaxyRadioAppWidgetProvider
			.getInstance();
	private final IBinder mBinder = new ServiceBinder();
	private BroadcastReceiver mIntentReceiver = new GalaxyServiceReceiver();
	private FMPlayerServiceWrapper mFmRadioServiceWrapper;
	private AudioManager mAudioService;
	private IFMRadioNotification mRadioNotification = new GalaxyRadioNotification();
	private String mFrequencyData = "";
	private String mStationData = "";
	private String mInfoData = "";
	private List<Long> scannedChannelList = new ArrayList<Long>();;
	private boolean isTuned;
	private Handler mRefreshHandler = new RefreshHandler();

	private void log(String msg) {
		Log.d(TAG, msg);
	}

	@Override
	public void onCreate() {
		super.onCreate();
		
		INSTANCE = this;

		log("service - onCreate");
		if (isRadioAppInstalled()) {
			log("service - onCreate, radio app present");
			
			mAudioService = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
	
			mFmRadioServiceWrapper = new FMPlayerServiceWrapper(
					getSystemService(FM_RADIO_SERVICE_NAME));
			mFmRadioServiceWrapper.setListener(mRadioNotification);
	
			prepareChannels();
		}
		
		IntentFilter intentFilter = new IntentFilter();
		intentFilter.addAction(SERVICECMDX);
		intentFilter.addAction(PREV_ACTION_INTERNAL);
		intentFilter.addAction(NEXT_ACTION_INTERNAL);
		intentFilter.addAction(TOGGLEPAUSE_ACTION_INTERNAL);
		intentFilter.addAction(SCAN_CHANNELS_ACTION_INTERNAL);
		registerReceiver(mIntentReceiver, intentFilter);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();

		log("service - onDestroy");
		
		INSTANCE = null;
		
		unregisterReceiver(mIntentReceiver);
	}

	@Override
	public IBinder onBind(Intent arg0) {
		log("service - onBind");

		return mBinder;
	}

	public boolean isRadioAppInstalled() {
		try {
			Class.forName("com.samsung.media.fmradio.FMEventListener");
			
			return true;
		} catch (ClassNotFoundException e) {
			return false;
		}
	}

	public class ServiceBinder extends Binder {
		public GalaxyRadioService getUpdatingService() {
			return GalaxyRadioService.this;
		}
	}

	public class GalaxyServiceReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			String cmd = intent.getStringExtra(CMDNAME);

			log("service - onReceive, action: " + action + ", cmd: " + cmd);

			if (SERVICECMDX.equals(action)) {
				if (CMDAPPWIDGETUPDATE.equals(cmd)) {
					int[] appWidgetIds = intent
							.getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS);
					GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
							GalaxyRadioService.this, appWidgetIds);
				}
			} else if (TOGGLEPAUSE_ACTION_INTERNAL.equals(action)) {
				if (isRadioPlaying() && !isScanInProgress()) {
					turnRadioOff();
				} else {
					play();
				}
			} else if (NEXT_ACTION_INTERNAL.equals(action)) {
				nextStation();
			} else if (PREV_ACTION_INTERNAL.equals(action)) {
				prevStation();
			} else if (SCAN_CHANNELS_ACTION_INTERNAL.equals(action)) {
				if (!isRadioPlaying() && !isScanInProgress()) {
					scanForChannels();
				} else if (isScanInProgress()) {
					mFmRadioServiceWrapper.stopScan();
				}
			}
		}
	}

	public boolean isRadioPlaying() {
		return mFmRadioServiceWrapper.isOn()
				&& !mFmRadioServiceWrapper.isScanning() && isTuned;
	}

	public boolean isScanInProgress() {
		return mFmRadioServiceWrapper.isScanning();
	}

	public String getFrequencyData() {
		return mFrequencyData;
	}

	public String getStationData() {
		return mStationData;
	}

	public String getInfoData() {
		return mInfoData;
	}

	private void nextStation() {
		if (isRadioPlaying()) {
			if (mFmRadioServiceWrapper.getCurrentChannel() != scannedChannelList.get(scannedChannelList.size() - 1)) {
				long nextFrequency = mFmRadioServiceWrapper.seekUp();
			}
		}
	}

	private void prevStation() {
		if (isRadioPlaying()) {
			if (mFmRadioServiceWrapper.getCurrentChannel() != scannedChannelList.get(0)) {
				long nextFrequency = mFmRadioServiceWrapper.seekDown();
			}
		}
	}

	private void scanForChannels() {
		if (turnRadioOn()) {
			mFmRadioServiceWrapper.scan();
		}
	}

	private void prepareChannels() {
		if (mFmRadioServiceWrapper.getLastScanResult() != null) {
			for (long freq : mFmRadioServiceWrapper.getLastScanResult()) {
				scannedChannelList.add(freq);
			}
		}
	}

	public boolean areChanelsAvailable() {
		return scannedChannelList != null && scannedChannelList.size() > 0;
	}

	private void play() {
		
		if (!turnRadioOn()) {
			return;
		}

		if (mFmRadioServiceWrapper.isScanning()) {
			Toast toast = Toast.makeText(this, R.string.scanning, 5);
			toast.show();

			return;
		}

		if (areChanelsAvailable()) {
			long lastPlayedFreq = WidgetConfigDatabase
					.getLastPlayedFrequency(this);

			if (lastPlayedFreq == 0) {
				// no last played frequency saved, so picking up the first
				// channel from the list
				lastPlayedFreq = scannedChannelList.get(0);
			}

			mFmRadioServiceWrapper.enableRDS();
			mFmRadioServiceWrapper.enableAF();
			mFmRadioServiceWrapper.tune(lastPlayedFreq);
			setUpRadioVolume();
		} else {
			Toast toast = Toast.makeText(this, R.string.no_channels, 5);
			toast.show();
		}
	}

	private boolean turnRadioOn() {
		if (!mFmRadioServiceWrapper.isOn()) {
			if (WidgetConfigDatabase.hasRadioRegionPref(this)) {
				try {
					mFmRadioServiceWrapper.on();
				} catch (FMPlayerException e) {
					Toast toast = Toast.makeText(this, R.string.error, 0);
					switch (e.getCode()) {
					case FMPlayerException.AIRPLANE_MODE:
						toast.setText(R.string.airplane_mode);
						break;
					case FMPlayerException.BATTERY_LOW:
						toast.setText(R.string.battery_low);
						break;
					case FMPlayerException.HEAD_SET_IS_NOT_PLUGGED:
						toast.setText(R.string.no_earphone);
						break;
					case FMPlayerException.PLAYER_SCANNING:
						toast.setText(R.string.scanning);
						break;
					case FMPlayerException.RADIO_SERVICE_DOWN:
						toast.setText(R.string.no_radio_service);
						break;
					case FMPlayerException.TV_OUT_PLUGGED:
						toast.setText(R.string.tvout_plugged);
						break;
					}
					toast.show();
					
					return false;
				}
				setUpRadioRegion();
			} else {
				Toast toast = Toast.makeText(this, R.string.location_missing, 0);
				toast.show();
				
				return false;
			}
		}
		
		return true;
	}

	private void turnRadioOff() {
		if (mFmRadioServiceWrapper.isOn()) {
			mFmRadioServiceWrapper.off();
		}
	}

	private void setUpRadioRegion() {
		String region = WidgetConfigDatabase.getRadioRegionPref(this);

		if (WidgetConfigDatabase.REGION_EUROPE.equals(region)) {
			mFmRadioServiceWrapper.setBand(BAND_87500_108000_kHz);
			mFmRadioServiceWrapper.setChannelSpacing(CHAN_SPACING_100_kHz);
			mFmRadioServiceWrapper.setDEConstant(DE_TIME_CONSTANT_50);
		} else if (WidgetConfigDatabase.REGION_USA.equals(region)) {
			mFmRadioServiceWrapper.setBand(BAND_87500_108000_kHz);
			mFmRadioServiceWrapper.setChannelSpacing(CHAN_SPACING_200_kHz);
			mFmRadioServiceWrapper.setDEConstant(DE_TIME_CONSTANT_75);
		} else if (WidgetConfigDatabase.REGION_JAPAN.equals(region)) {
			mFmRadioServiceWrapper.setBand(BAND_76000_108000_kHz);
			mFmRadioServiceWrapper.setChannelSpacing(CHAN_SPACING_100_kHz);
			mFmRadioServiceWrapper.setDEConstant(DE_TIME_CONSTANT_50);
		}
	}

	private void setUpRadioVolume() {
		mFmRadioServiceWrapper.setSpeakerOn(false);

		int vol = mAudioService.getStreamVolume(RADIO_AUDIO_STREAM);
		mAudioService.setStreamVolume(RADIO_AUDIO_STREAM, vol, 0x0);
	}

	public class GalaxyRadioNotification implements IFMRadioNotification {

		@Override
		public void onEarPhoneConnected() {
			// TODO Auto-generated method stub

		}

		@Override
		public void onEarPhoneDisconnected() {
			mFrequencyData = "";
			mStationData = "";
			mInfoData = "";
			isTuned = false;

			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}

		@Override
		public void onOff() {
			mFrequencyData = "";
			mStationData = "";
			mInfoData = "";
			isTuned = false;

			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}

		@Override
		public void onOn() {
			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}

		@Override
		public void onRDSDisabled() {
			mStationData = "";
			mInfoData = "";

			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}

		@Override
		public void onRDSEnabled() {
			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}

		@Override
		public void onRDSReceived(long freq, String stationName,
				String radioText) {
			mStationData = stationName;
			mInfoData = radioText;

			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}

		@Override
		public void onScanStarted() {
			scannedChannelList.clear();
			isTuned = false;
			
			log("service - onScanStarted");
			
			WidgetConfigDatabase.setLastPlayedFrequency(
					GalaxyRadioService.this, 0);

			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}
		
		@Override
		public void onChannelFound(long freq) {
			log("service - onChannelFound: " + freq);
			
			scannedChannelList.add(freq);
		}

		@Override
		public void onScanFinished(long[] freqs) {
			log("service - onScanFinished");

			mRefreshHandler.sendEmptyMessageDelayed(0, 100);
		}

		@Override
		public void onScanStopped(long[] freqs) {
			log("service - onScanStopped");
			
			mRefreshHandler.sendEmptyMessageDelayed(0, 100);
		}

		@Override
		public void onTune(long freq) {
			String rawFreq = Long.toString(freq / 10);
			
			log("service - onTune: " + freq);
			
			if (rawFreq.length() > 1) {
				mFrequencyData = rawFreq.substring(0, rawFreq.length() - 2)
						+ "."
						+ rawFreq.substring(rawFreq.length() - 2,
								rawFreq.length()) + " Mhz";
			}
			mStationData = "";
			mInfoData = "";
			isTuned = true;

			WidgetConfigDatabase.setLastPlayedFrequency(
					GalaxyRadioService.this, freq);

			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}
	}
	
	public class RefreshHandler extends Handler {
		@Override
		public void handleMessage(Message msg) {
			super.handleMessage(msg);
			
			GalaxyRadioService.this.mAppWidgetProvider.performUpdate(
					GalaxyRadioService.this, null);
		}
	}
}
